package org.xnat.xnatfs.webdav;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import org.junit.Before;
import org.junit.Test;
import org.xnat.xnatfs.asset.IAssetProvider;
import org.xnat.xnatfs.asset.IStreamAsset;
import org.xnat.xnatfs.asset.StreamUtils;

import com.bradmcevoy.http.Auth;

public class TestRemoteFile {
  private static final String restUrl = "/projects/Demo/subjects/Sample_Patient/experiments/SampleID/scans/4/resources/SNAPSHOTS/files/SampleID_4_qc.gif";

  private IStreamAsset asset;
  private RemoteFile resource;
  private XNATFS xnatfs;
  private IAssetProvider assetProvider;
  private ByteArrayOutputStream outStream;

  @Before
  public void setUp () throws Exception {
    outStream = new ByteArrayOutputStream ();

    asset = mock ( IStreamAsset.class );
    when ( asset.found () ).thenReturn ( true );

    assetProvider = mock ( IAssetProvider.class );
    when ( assetProvider.getStreamAsset ( eq ( restUrl ), any ( Auth.class ) ) ).thenReturn ( asset );

    xnatfs = mock ( XNATFS.class );
    when ( xnatfs.getAssetProvider () ).thenReturn ( assetProvider );
    when ( xnatfs.getAuth () ).thenReturn ( new Auth ( "someuser" ) );

    resource = new RemoteFile ( xnatfs, "/Projects/Demo/Subjects/Sample_Patient/Experiments/SampleID/Scans/4/Resources/SNAPSHOTS", "SampleID_4_qc.gif", restUrl, 0L );
  }

  @Test
  public void shouldSendContent () throws Exception {
    when ( asset.getContent () ).thenReturn ( StreamUtils.toStream ( "hello world" ) );

    resource.sendContent ( outStream, null, null, null );

    assertEquals ( "hello world", outStream.toString () );
    verify ( asset ).close ();
  }

  @Test
  public void shouldProvideContentLength () throws Exception {
    when ( assetProvider.getAssetHead ( eq ( restUrl ), any ( Auth.class ) ) ).thenReturn ( asset );
    when ( asset.getContentLength () ).thenReturn ( 64L );

    assertEquals ( Long.valueOf ( 64L ), resource.getContentLength () );
  }

  @Test
  public void shouldContinuePastCloseException () throws Exception {
    when ( asset.getContent () ).thenReturn ( StreamUtils.toStream ( "hello world" ) );
    doThrow ( new IOException ( "fake error" ) ).when ( asset ).close ();

    resource.sendContent ( outStream, null, null, null );

    assertEquals ( "hello world", outStream.toString () );
  }

  @Test
  public void shouldCloseOnException () throws Exception {
    when ( asset.getContent () ).thenThrow ( new IOException ( "fake error" ) );

    try {
      resource.sendContent ( outStream, null, null, null );
      fail ( "Expected exception" );
    } catch ( IOException e ) {
      verify ( asset ).close ();
    }
  }
}
